import { app, BrowserWindow, shell, ipcMain, globalShortcut, Menu, dialog } from "electron"
import { setupHttpProxy } from "./http-proxy"
import { createRequire } from "node:module"
import { fileURLToPath } from "node:url"
import path from "node:path"
import os from "node:os"
import { spawn, ChildProcess } from "child_process"
import Store from "electron-store"
import { logger, logSystemInfo, logShutdown, openLogsDirectory } from "./logger"
import fs from "fs"
import { errorHandler } from "./error-handler"
import { mqttService } from "./mqtt-service"
import { c } from "vite/dist/node/types.d-aGj9QkWt"
// 定义Store类型，避免类型错误
interface StoreInterface {
  name: string
  defaults: Record<string, any>
}

// 创建用于管理Store实例的函数
function createNamedStore(name: string): Store {
  return new Store({
    name,
    defaults: {},
    // 与Node脚本保持一致的关键配置 - 指定相同的项目名称
    projectName: "electron-store-nodejs",
    // 指定相同的配置文件夹名称
    cwd: path.join(os.homedir(), "AppData", "Roaming", "electron-store-nodejs", "Config"),
  } as any) // 使用as any暂时绕过类型检查
}

const require = createRequire(import.meta.url)
const __dirname = path.dirname(fileURLToPath(import.meta.url))

// The built directory structure
//
// ├─┬ dist-electron
// │ ├─┬ main
// │ │ └── index.js    > Electron-Main
// │ └─┬ preload
// │   └── index.mjs   > Preload-Scripts
// ├─┬ dist
// │ └── index.html    > Electron-Renderer
//
process.env.APP_ROOT = path.join(__dirname, "../..")

export const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron")
export const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist")
export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL

process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, "public") : RENDERER_DIST

// Disable GPU Acceleration for Windows 7
if (os.release().startsWith("6.1")) app.disableHardwareAcceleration()

// Set application name for Windows 10+ notifications
if (process.platform === "win32") app.setAppUserModelId(app.getName())

// 确保只有一个实例在运行
if (!app.requestSingleInstanceLock()) {
  logger.info("另一个实例已在运行，退出当前实例")
  app.quit()
  process.exit(0)
}

// 确保所有窗口都被正确关闭
let allWindows: BrowserWindow[] = []
let forceQuit = false

let win: BrowserWindow | null = null
const preload = path.join(__dirname, "../preload/index.mjs")
const indexHtml = path.join(RENDERER_DIST, "index.html")

let automationProcess: ChildProcess | null = null
let isAutomationRunning = false

// Add isQuitting property to track when app is quitting
app.isQuitting = false

// 启动自动化服务
function startAutomationService(data: any) {
  if (isAutomationRunning) {
    console.log("自动化服务已经在运行中")
    logger.info("自动化服务已经在运行中")
    return
  }

  // 解决生产环境中的路径问题
  let mainScriptPath = ""
  let launcherPath = ""
  let nodeExecutablePath = ""

  if (app.isPackaged) {
    // 生产环境 - 使用extraResources目录下的脚本
    // 此路径是基于electron-builder.json5中的配置
    mainScriptPath = path.join(process.resourcesPath, "scripts", "ads_puppeteer.js")
    launcherPath = path.join(process.resourcesPath, "scripts", "module-launcher.mjs")
    // 根据操作系统确定node可执行文件路径
    if (process.platform === "win32") {
      nodeExecutablePath = path.join(process.resourcesPath, "node", "node.exe")
    } else {
      nodeExecutablePath = path.join(process.resourcesPath, "node", "node")
    }
    logger.info(`生产环境使用路径: ${mainScriptPath}`)
    logger.info(`使用Node可执行文件: ${nodeExecutablePath}`)
  } else {
    // 开发环境 - 使用原始路径
    mainScriptPath = path.join(process.env.APP_ROOT, "src/puppeteer_ads/ads_puppeteer.js")
    launcherPath = path.join(process.env.APP_ROOT, "src/puppeteer_ads/module-launcher.mjs")
    // 开发环境下依赖系统的node命令
    nodeExecutablePath = "node"
    logger.info(`开发环境使用路径: ${mainScriptPath}`)
  }

  logger.info(`准备启动自动化服务，主脚本: ${mainScriptPath}, 启动器: ${launcherPath}`)

  // 首先检查启动器脚本是否存在
  if (!fs.existsSync(launcherPath)) {
    const errorMsg = `启动器脚本不存在: ${launcherPath}`
    logger.error(errorMsg)
    console.error(errorMsg)
    return
  }

  // 检查主脚本文件是否存在
  if (!fs.existsSync(mainScriptPath)) {
    const errorMsg = `自动化脚本文件不存在: ${mainScriptPath}`
    logger.error(errorMsg)
    console.error(errorMsg)

    // 在生产环境中尝试输出更多调试信息
    if (app.isPackaged) {
      logger.error(`当前执行路径: ${process.execPath}`)
      logger.error(`应用路径: ${app.getAppPath()}`)
      logger.error(`资源路径: ${process.resourcesPath}`)

      // 尝试列出资源目录内容
      try {
        const resourcesDir = process.resourcesPath
        if (fs.existsSync(resourcesDir)) {
          const files = fs.readdirSync(resourcesDir)
          logger.info(`资源目录内容: ${files.join(", ")}`)

          // 检查scripts目录
          const scriptsDir = path.join(resourcesDir, "scripts")
          if (fs.existsSync(scriptsDir)) {
            const scriptFiles = fs.readdirSync(scriptsDir)
            logger.info(`scripts目录内容: ${scriptFiles.join(", ")}`)
          } else {
            logger.error(`scripts目录不存在`)
          }
        }
      } catch (err) {
        logger.error(`列出资源目录失败: ${err.message || err}`)
      }
    }

    return
  }

  // 如果是打包环境，检查Node可执行文件是否存在
  if (app.isPackaged && nodeExecutablePath !== "node") {
    if (!fs.existsSync(nodeExecutablePath)) {
      const errorMsg = `Node可执行文件不存在: ${nodeExecutablePath}`
      logger.error(errorMsg)
      console.error(errorMsg)

      // 尝试列出node目录内容
      try {
        const nodeDir = path.dirname(nodeExecutablePath)
        if (fs.existsSync(nodeDir)) {
          const files = fs.readdirSync(nodeDir)
          logger.info(`Node目录内容: ${files.join(", ")}`)
        } else {
          logger.error(`Node目录不存在: ${nodeDir}`)
        }
      } catch (err) {
        logger.error(`列出Node目录失败: ${err.message || err}`)
      }

      // 找不到内置Node，尝试回退使用系统的node命令
      logger.info("找不到内置Node，尝试使用系统node命令")
      nodeExecutablePath = "node"
    }
  }

  try {
    // 确定node_modules路径
    let nodeModulesPath = ""
    if (app.isPackaged) {
      // 使用打包后的路径
      // 1. 先尝试dist-electron/node_modules
      const distElectronModules = path.join(app.getAppPath(), "..", "dist-electron", "node_modules")
      // 2. 再尝试resources/node_modules
      const resourcesModules = path.join(process.resourcesPath, "node_modules")

      if (fs.existsSync(distElectronModules)) {
        nodeModulesPath = distElectronModules
        logger.info(`使用dist-electron中的node_modules: ${nodeModulesPath}`)
      } else if (fs.existsSync(resourcesModules)) {
        nodeModulesPath = resourcesModules
        logger.info(`使用resources中的node_modules: ${nodeModulesPath}`)
      } else {
        logger.warn("找不到有效的node_modules路径")
      }
    } else {
      // 开发环境，使用项目根目录的node_modules
      nodeModulesPath = path.join(process.env.APP_ROOT, "node_modules")
      logger.info(`开发环境使用node_modules: ${nodeModulesPath}`)
    }

    // 将数据保存到electron-store
    console.log("数据为：===>", data)
    try {
      console.log("数据为：===>", JSON.parse(data))
    } catch (e) {
      console.log("解析数据失败，使用原始数据", e)
    }

    // 创建专用于自动化任务的Store实例
    const automationTasksStore = createNamedStore("automation-tasks")

    // 保存当前任务数据
    automationTasksStore.set("windowRunData", {
      timestamp: Date.now(),
      data: data,
    })

    logger.info(`已将任务数据保存到electron-store，任务ID: ${"windowRunData"}`)
    console.log(`已将任务数据保存到electron-store，任务ID: ${"windowRunData"}`)

    // 构建一个完整的环境变量对象，包括原始process.env以及额外的变量
    const env = {
      ...process.env,
      // 添加应用资源路径，以便子进程可以找到其他相关资源
      APP_RESOURCE_PATH: process.resourcesPath,
      // 指示这是一个打包的环境
      IS_PACKAGED: String(app.isPackaged),
      // 确保Node.js知道这是一个ES模块
      NODE_OPTIONS: "--experimental-modules --es-module-specifier-resolution=node",
      // 设置NODE_PATH来帮助Node.js找到模块
      NODE_PATH: nodeModulesPath,
      // 指定使用 puppeteer-core 而不是 puppeteer
      PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true",
      // 跳过下载 Chromium
      PUPPETEER_SKIP_DOWNLOAD: "true",
      // 添加任务ID，用于ads_puppeteer.js从electron-store中获取数据
      TASK_ID: "windowRunData",
      // 隐藏Node.js实验性功能警告
      NODE_NO_WARNINGS: "1",
    }

    // 输出重要的环境信息以便调试
    logger.info(`启动环境: NODE_PATH=${nodeModulesPath}`)
    logger.info(`启动环境: APP_RESOURCE_PATH=${process.resourcesPath}`)
    logger.info(`启动环境: IS_PACKAGED=${app.isPackaged}`)
    logger.info(`启动环境: TASK_ID=${"windowRunData"}`)

    // 使用启动器脚本执行主脚本，修改stdio设置以避免EPIPE错误
    automationProcess = spawn(nodeExecutablePath, [launcherPath, `mode=${import.meta.env.MODE}`, `windowRunData=${"windowRunData"}`], {
      // 使用 pipe 模式允许向子进程发送消息
      stdio: ["pipe", "pipe", "pipe"],
      shell: true,
      detached: false,
      env: env,
    })

    isAutomationRunning = true
    console.log("自动化服务已启动，进程ID:", automationProcess.pid)
    logger.info(`自动化服务已启动，进程ID: ${automationProcess.pid}`)

    // 当自动化服务启动时，订阅MQTT主题
    try {
      logger.info("[MQTT Service] 启动自动化服务时连接MQTT服务器并订阅主题")
      // 确保设备ID列表已设置好
      if (data && typeof data === "string") {
        try {
          const parsedData = JSON.parse(data)
          console.log("parsedData====>", parsedData)
          console.log("parsedData类型:", typeof parsedData)
          console.log("parsedData.action:", parsedData.action)
          console.log("parsedData.deviceIdList:", parsedData.deviceIdList)

          // 如果有设备ID列表，先设置它
          if (parsedData.deviceIdList && Array.isArray(parsedData.deviceIdList)) {
            mqttService.setDeviceIdList(parsedData.deviceIdList)

            // 确保MQTT已连接
            if (!mqttService.getConnectionStatus()) {
              logger.info("[MQTT Service] MQTT未连接，正在连接...")
              // 设置环境，确保连接到正确的服务器
              if (parsedData.mode) {
                mqttService.setMode(parsedData.mode)
              }
              // 连接MQTT服务器
              mqttService.connect()
              // 给连接一些时间建立
              setTimeout(() => {
                // 延迟执行订阅，确保连接已建立
                if (mqttService.getConnectionStatus()) {
                  mqttService.subscribeToDeviceTopics()
                  logger.info(`[MQTT Service] 已为设备列表订阅主题: ${parsedData.deviceIdList.join(", ")}`)
                } else {
                  logger.warn("[MQTT Service] MQTT连接未建立，无法订阅主题")
                }
              }, 2000)
            } else {
              // 已连接，直接调用订阅方法
              mqttService.subscribeToDeviceTopics()
              logger.info(`[MQTT Service] 已为设备列表订阅主题: ${parsedData.deviceIdList.join(", ")}`)
            }
          }
        } catch (e) {
          logger.error(`[MQTT Service] 解析设备ID列表失败: ${e.message}`)
        }
      }
    } catch (error) {
      logger.error(`[MQTT Service] 订阅MQTT主题时出错: ${error.message || error}`)
    }

    // 设置MQTT消息转发
    if (automationProcess && automationProcess.stdin) {
      // 设置事件处理程序来转发MQTT消息
      ipcMain.on("mqtt-message", (event) => {
        if (automationProcess && !automationProcess.killed && automationProcess.stdin) {
          try {
            const message =
              JSON.stringify({
                type: "mqtt-message",
                data: event,
              }) + "\n"
            automationProcess.stdin.write(message)
            logger.info(`[MQTT Service] Forwarded message to automation process: ${message.substring(0, 100)}${message.length > 100 ? "..." : ""}`)
          } catch (error) {
            logger.error(`[MQTT Service] Failed to forward message to automation process: ${error.message || error}`)
          }
        }
      })
    } else {
      logger.warn("[MQTT Service] Automation process stdin is not available, MQTT messages will not be forwarded")
    }

    automationProcess.stdout.on("data", (data: Buffer) => {
      const lines = data.toString().split("\n").filter(Boolean) // 多行输出兼容
      for (const line of lines) {
        try {
          const message = JSON.parse(line)

          // 判断是不是来自自动化脚本 + 指定类型
          if (message.source === "automation-script" && ["bind-account-done", "run-task-done", "send-node-error"].includes(message.type)) {
            win.webContents.send(message.type, message)
          } else {
            // 不是目标消息，忽略
            console.log("忽略消息:", line)
          }
        } catch (err) {
          // 非 JSON 输出忽略
          console.warn("无法解析的消息:", data.toString())
        }
      }
    })
    // 处理输出
    if (automationProcess.stdout) {
      // 创建一个缓存用于存储最近处理的消息，避免重复处理
      const recentMessages = new Set()
      const MESSAGE_CACHE_SIZE = 50 // 记住最近50条消息

      automationProcess.stdout.on("data", (data: Buffer) => {
        const output = data.toString()

        // 对纯文本输出进行简单过滤，避免重复输出相同的日志
        if (output.includes("[自动化服务] 收到MQTT消息")) {
          // 检查这条消息是否已经处理过
          if (recentMessages.has(output)) {
            // 已经处理过的相同消息，不再重复处理
            return
          }

          // 将消息加入缓存
          recentMessages.add(output)

          // 如果缓存过大，清理旧消息
          if (recentMessages.size > MESSAGE_CACHE_SIZE) {
            const iterator = recentMessages.values()
            recentMessages.delete(iterator.next().value)
          }

          // 只打印一次
          console.log(`自动化服务MQTT消息: ${output.substring(0, 100)}${output.length > 100 ? "..." : ""}`)
          return
        }

        // 常规输出正常处理
        console.log(`自动化服务输出: ${output}`)

        // 尝试解析JSON格式的消息
        try {
          if (output.includes('"type":"mqtt-action"')) {
            const mqttAction = JSON.parse(output)
            if (mqttAction.source === "node-script" && mqttAction.type === "mqtt-action") {
              logger.info(`[MQTT Service] 收到来自Node脚本的MQTT操作请求: ${mqttAction.action}`)

              // 处理不同的MQTT操作
              switch (mqttAction.action) {
                case "connect":
                  // 确保MQTT已连接
                  if (!mqttService.getConnectionStatus()) {
                    logger.info("[MQTT Service] 根据Node脚本请求连接MQTT")
                    mqttService.connect()
                  } else {
                    logger.info("[MQTT Service] MQTT已经连接")
                  }
                  break

                case "disconnect":
                  // 断开MQTT连接
                  if (mqttService.getConnectionStatus()) {
                    logger.info("[MQTT Service] 根据Node脚本请求断开MQTT")
                    mqttService.disconnect()
                  }
                  break

                case "subscribe":
                  // 订阅主题
                  if (mqttAction.topics && mqttService.getConnectionStatus()) {
                    logger.info(`[MQTT Service] 根据Node脚本请求订阅主题: ${mqttAction.topics}`)
                    mqttService.subscribe(mqttAction.topics)
                  }
                  break

                default:
                  logger.warn(`[MQTT Service] 未知的MQTT操作请求: ${mqttAction.action}`)
              }
            }
          }
        } catch (e) {
          // 忽略非JSON格式的输出，但不再打印"无法解析的消息"警告
          // 只有在调试模式下才输出解析错误
          if (process.env.NODE_ENV === "development") {
            console.debug(`调试信息: 无法解析JSON: ${e.message}`)
          }
        }
      })
    }

    // Process automation errors
    if (automationProcess.stderr) {
      automationProcess.stderr.on("data", (data: Buffer) => {
        const errorMessage = data.toString()
        console.error(`自动化服务错误: ${errorMessage}`)
        logger.error(`自动化服务错误: ${errorMessage}`)

        // Capture and forward to renderer
        captureAutomationError({
          message: errorMessage,
          info: { processId: automationProcess?.pid },
        })
      })
    }

    // 处理进程退出
    automationProcess.on("close", (code: number, signal: string) => {
      console.log(`自动化服务退出，退出码: ${code}, 信号: ${signal}`)
      isAutomationRunning = false
      automationProcess = null
    })

    automationProcess.on("error", (error) => {
      isAutomationRunning = false
      console.error(`自动化服务启动失败: ${error.message}`)
      logger.error(`自动化服务启动失败: ${error.message}`, { error })

      // Capture and forward to renderer
      captureAutomationError(error)
    })

    automationProcess.on("exit", (code, signal) => {
      isAutomationRunning = false

      if (code !== 0) {
        const message = `自动化服务异常退出，代码: ${code}, 信号: ${signal}`
        console.error(message)
        logger.error(message)

        // Capture and forward to renderer
        captureAutomationError({
          message,
          info: { code, signal, processId: automationProcess?.pid },
        })
      } else {
        console.log(`自动化服务正常退出，代码: ${code}`)
        logger.info(`自动化服务正常退出，代码: ${code}`)
      }

      automationProcess = null
    })

    // 处理未捕获的异常
    automationProcess.on("uncaughtException", (error: Error) => {
      console.error("自动化服务未捕获的异常:", error)
    })
  } catch (error) {
    console.error("启动自动化服务时出错:", error)
    isAutomationRunning = false

    // Capture and forward to renderer
    captureAutomationError(error)
  }
}

// 停止自动化服务
async function stopAutomationService() {
  if (!automationProcess || !isAutomationRunning) {
    console.log("自动化服务未运行")
    logger.info("尝试停止自动化服务，但服务未运行")
    return
  }

  try {
    console.log("正在停止自动化服务...")
    logger.info("正在停止自动化服务...")

    // 停止自动化服务时取消MQTT订阅
    try {
      logger.info("[MQTT Service] 停止自动化服务前取消所有MQTT订阅")
      mqttService.unsubscribeAll()
    } catch (error) {
      logger.error(`[MQTT Service] 取消MQTT订阅时出错: ${error.message || error}`)
    }

    // 创建一个Promise，等待子进程通知窗口关闭完成或超时
    const windowsClosedPromise = new Promise<boolean>((resolve) => {
      // 设置一个标志，表示是否已收到关闭完成的消息
      let closedSuccessfully = false

      // 监听子进程的标准输出，检测窗口关闭完成的消息
      if (automationProcess && automationProcess.stdout) {
        automationProcess.stdout.on("data", (data: Buffer) => {
          const message = data.toString()
          if (message.includes("[自动化服务] 所有浏览器窗口已关闭") || message.includes("[绑定账号] 所有浏览器窗口已处理完毕")) {
            console.log("接收到窗口关闭完成消息")
            closedSuccessfully = true
            resolve(true)
          }
        })
      }

      // 设置最大等待时间（10秒）
      setTimeout(() => {
        if (!closedSuccessfully) {
          console.log("等待窗口关闭超时，将强制终止进程")
          resolve(false)
        }
      }, 10000)
    })

    // 由于我们将stdin设为'ignore'，无法通过stdin发送关闭命令
    // 直接尝试使用信号关闭进程

    // Windows平台特殊处理
    if (process.platform === "win32") {
      try {
        console.log("尝试查找并关闭所有残留的Chrome浏览器进程...")
        // 使用tasklist查找所有Chrome进程
        const findChromeCommand = spawn("tasklist", ["/FI", "IMAGENAME eq chrome.exe", "/FO", "LIST"], {
          shell: true,
          stdio: "pipe",
        })

        let chromeProcessData = ""
        findChromeCommand.stdout.on("data", (data) => {
          chromeProcessData += data.toString()
        })

        // 等待命令执行完成
        await new Promise<void>((resolve) => {
          findChromeCommand.on("close", () => {
            resolve()
          })
        })

        // 查找所有PID
        const pidRegex = /PID:\s+(\d+)/g
        let match
        const chromePids = []
        while ((match = pidRegex.exec(chromeProcessData)) !== null) {
          chromePids.push(match[1])
        }

        if (chromePids.length > 0) {
          console.log(`找到 ${chromePids.length} 个Chrome进程，正在关闭...`)
          // 关闭所有找到的Chrome进程
          for (const pid of chromePids) {
            try {
              spawn("taskkill", ["/PID", pid, "/F"], {
                shell: true,
                stdio: "ignore",
              })
            } catch (err) {
              console.error(`关闭Chrome进程 ${pid} 时出错:`, err)
            }
          }

          // 给进程一些时间关闭
          await new Promise((resolve) => setTimeout(resolve, 2000))
        } else {
          console.log("未找到运行中的Chrome进程")
        }
      } catch (err) {
        console.error("查找或关闭Chrome进程时出错:", err)
      }
    } else if (automationProcess && automationProcess.pid) {
      // 非Windows平台，尝试使用SIGUSR1信号
      try {
        console.log("尝试通过信号通知自动化服务关闭浏览器窗口...")
        process.kill(automationProcess.pid, "SIGUSR1")
        // 等待一段时间
        await new Promise((resolve) => setTimeout(resolve, 3000))
      } catch (err) {
        console.error("发送信号失败:", err)
      }
    }

    // 等待一段时间后强制终止进程
    await new Promise((resolve) => setTimeout(resolve, 2000))

    // 在 Windows 上，我们需要使用 taskkill 来确保子进程及其所有子进程都被终止
    if (process.platform === "win32" && automationProcess.pid) {
      spawn("taskkill", ["/pid", automationProcess.pid.toString(), "/f", "/t"], {
        shell: true,
        stdio: "ignore",
      })
    } else {
      // 在其他平台上，我们可以使用 kill 方法
      automationProcess.kill("SIGTERM")

      // 如果进程在 5 秒内没有退出，强制终止它
      setTimeout(() => {
        if (automationProcess && isAutomationRunning) {
          console.log("强制终止自动化服务")
          automationProcess.kill("SIGKILL")
        }
      }, 5000)
    }

    isAutomationRunning = false
  } catch (error) {
    console.error("停止自动化服务时出错:", error)
    logger.error(`停止自动化服务时出错: ${error.message || error}`)
  }
}

async function createWindow() {
  logger.info("正在创建应用主窗口")
  win = new BrowserWindow({
    width: 1200, // 默认宽度
    height: 800, // 默认高度
    minWidth: 800, // 最小宽度（可选）
    minHeight: 600, // 最小高度（可选）
    resizable: true, // 是否可调整大小（默认 true）
    title: "Main window",
    icon: path.join(process.env.VITE_PUBLIC, "favicon.ico"),
    webPreferences: {
      preload,
      // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
      nodeIntegration: true,

      // Consider using contextBridge.exposeInMainWorld
      // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
      // contextIsolation: false,
      // webSecurity: false // 禁用 web 安全策略，允许加载 blob 脚本
    },
    autoHideMenuBar: true, // ✅ 自动隐藏菜单栏
  })
  allWindows.push(win) // 追踪创建的窗口
  logger.info("窗口已创建")

  // Initialize error handler with the main window
  errorHandler.initialize(win)

  // 监听窗口关闭事件，移除对应的窗口引用
  win.on("closed", () => {
    logger.info("主窗口被关闭，移除窗口引用")
    allWindows = allWindows.filter((w) => w !== win)
    win = null
  })

  // 处理窗口关闭按钮点击事件
  win.on("close", (event) => {
    if (!forceQuit) {
      event.preventDefault() // 阻止默认的关闭行为
      logger.info("用户点击了关闭按钮，准备执行清理操作")

      // 显示确认对话框，使用主进程的dialog API
      dialog
        .showMessageBox(win, {
          type: "question",
          buttons: ["确定退出", "取消"],
          defaultId: 1,
          cancelId: 1, // 设置取消按钮ID为1，这样点击X也会映射到取消操作
          title: "确认退出",
          message: "确定要退出应用吗？",
          detail: "退出后所有正在运行的任务将被终止。\n\n如果有任务在运行，请务必先停止运行\n\n以免造成数据丢失！！！",
        })
        .then(({ response }) => {
          if (response === 0) {
            // 用户点击了"确定退出"
            logger.info("用户确认退出应用")
            // 先隐藏窗口，让用户感觉已经关闭了
            win.hide()
            // 执行干净的退出
            performCleanExit()
          } else {
            // response = 1 是"取消"按钮，或者点击了对话框的X关闭按钮
            logger.info("用户取消退出应用或关闭了对话框")
            // 如果用户取消，不做任何操作，窗口会保持打开状态
          }
        })
        .catch((err) => {
          logger.error(`显示确认对话框失败: ${err.message || err}`)
          // 出错时不自动退出，让用户决定是否重试
        })
    }
  })

  // 设置HTTP请求转发
  setupHttpProxy()
  logger.info("HTTP代理已设置")

  // 设置拦截器处理CORS问题
  win.webContents.session.webRequest.onHeadersReceived((details, callback) => {
    callback({
      responseHeaders: {
        ...details.responseHeaders,
        "Access-Control-Allow-Origin": ["*"],
        "Access-Control-Allow-Methods": ["GET, POST, PUT, DELETE, OPTIONS"],
        "Access-Control-Allow-Headers": ["X-Requested-With, Content-Type, Authorization, tenant-id"],
      },
    })
  })
  // 注册快捷键 Ctrl+Shift+I 来打开 DevTools
  globalShortcut.register("Ctrl+Shift+I", () => {
    win.webContents.openDevTools()
  })
  if (VITE_DEV_SERVER_URL) {
    // #298
    win.loadURL(VITE_DEV_SERVER_URL)
    // Open devTool if the app is not packaged
    // win.webContents.openDevTools()
  } else {
    win.loadFile(indexHtml)
  }

  // Test actively push message to the Electron-Renderer
  win.webContents.on("did-finish-load", () => {
    win?.webContents.send("main-process-message", new Date().toLocaleString())
  })

  // Make all links open with the browser, not with the application
  win.webContents.setWindowOpenHandler(({ url }) => {
    if (url.startsWith("https:")) shell.openExternal(url)
    return { action: "deny" }
  })
  // win.webContents.on('will-navigate', (event, url) => { }) #344

  // 添加重定向到登录页面的IPC处理器
  ipcMain.on("redirect-to-login", () => {
    console.log("主进程收到重定向到登录页请求", `file://${indexHtml}`)
    if (win && !win.isDestroyed()) {
      // 在主线程中执行重定向
      const url = VITE_DEV_SERVER_URL || `file://${indexHtml}`
      if (VITE_DEV_SERVER_URL) {
        win.loadURL(`${url}#/login`)
        console.log("已执行重定向到:", `${url}#/login`)
      } else {
        win.loadFile(indexHtml)
        console.log("已执行重定向到:", indexHtml)
      }
    }
  })
}

// 在应用启动时启动自动化服务
app.whenReady().then(() => {
  // 初始化日志系统并记录系统信息
  logSystemInfo()
  logger.info("应用程序正在启动")

  // 创建应用菜单，添加明确的退出选项
  createApplicationMenu()

  // 添加进程信号处理
  setupProcessSignalHandlers()

  // 设置MQTT IPC处理程序
  setupMqttIpcHandlers()

  createWindow()
  // 延迟启动自动化服务，确保主窗口已经创建
  // setTimeout(() => {
  //   startAutomationService();
  // }, 2000);
})

// 在应用退出时停止自动化服务
app.on("window-all-closed", async () => {
  logger.info("所有窗口已关闭")

  // 如果不是macOS，则执行干净退出
  // 在macOS上，应用通常保持活跃状态，直到用户通过Cmd+Q明确退出
  if (process.platform !== "darwin") {
    // 在该事件中不直接调用app.quit()，因为我们想要干净地退出
    // 会在performCleanExit中调用app.quit()
    await performCleanExit()
  }
})

// 添加 before-quit 事件处理，确保在应用退出前清理所有资源
app.on("before-quit", async (event) => {
  // 如果已经在执行forceQuit，则不阻止退出
  if (forceQuit) return

  // 设置退出标志
  app.isQuitting = true

  // 防止应用立即退出，等待清理完成
  event.preventDefault()
  logger.info("应用收到退出请求，正在准备干净退出")

  // 执行干净退出
  await performCleanExit()
})

app.on("second-instance", () => {
  if (win) {
    // Focus on the main window if the user tried to open another
    if (win.isMinimized()) win.restore()
    win.focus()
  }
})

app.on("activate", () => {
  const allWindows = BrowserWindow.getAllWindows()
  if (allWindows.length) {
    allWindows[0].focus()
  } else {
    createWindow()
  }
})
// New window example arg: new windows url
ipcMain.handle("open-win", (_, arg) => {
  const childWindow = new BrowserWindow({
    webPreferences: {
      preload,
      nodeIntegration: true,
      contextIsolation: false,
    },
  })

  // 追踪新创建的子窗口
  allWindows.push(childWindow)

  // 监听子窗口关闭事件，移除对应的窗口引用
  childWindow.on("closed", () => {
    allWindows = allWindows.filter((w) => w !== childWindow)
  })

  if (VITE_DEV_SERVER_URL) {
    childWindow.loadURL(`${VITE_DEV_SERVER_URL}#${arg}`)
  } else {
    childWindow.loadFile(indexHtml, { hash: arg })
  }
})

// 添加 IPC 通信处理
ipcMain.handle("start-automation", async (event, data) => {
  try {
    logger.info("收到启动自动化服务请求")
    startAutomationService(data)
    return { success: true }
  } catch (error) {
    console.error("启动自动化服务失败:", error)
    logger.error(`启动自动化服务失败: ${error.message || error}`)
    return { success: false }
  }
})

ipcMain.handle("stop-automation", async () => {
  logger.info("收到停止自动化服务请求")
  await stopAutomationService()
  return { success: true, isRunning: isAutomationRunning }
})

ipcMain.handle("get-automation-status", () => {
  logger.info("收到获取自动化服务状态请求")
  return { isRunning: isAutomationRunning }
})
// 将handle改为on，与前端的send调用匹配
ipcMain.on("win-reload", () => {
  logger.info("收到窗口重新加载请求")
  if (win && !win.isDestroyed()) {
    win.reload() // 更稳定地重新加载
    console.log("已执行窗口重新加载")
    logger.info("已执行窗口重新加载")
  }
})

// 添加清理缓存的处理器
ipcMain.on("clear-cache", () => {
  console.log("开始查询和清理缓存...")
  logger.info("收到清理缓存请求，开始查询缓存状态")
  if (win && !win.isDestroyed()) {
    console.log("正在检查应用缓存...")
    logger.info("正在检查应用缓存...")
    try {
      // 使用Node.js脚本相同的store配置
      const commentCyclesStore = createNamedStore("comment-cycles")
      const postingIntervalsStore = createNamedStore("posting-intervals")
      const addFbGroupCountObjStore = createNamedStore("fb_join_group_count")
      const fbPostingGroupCycleStore = createNamedStore("fb_posting_to_group_main")
      const tkLiveHomeFollowStore = createNamedStore("tk-live-home-follow")
      // 打印存储路径
      console.log("评论周期存储路径:", (commentCyclesStore as any).path)
      logger.info(`评论周期存储路径: ${(commentCyclesStore as any).path}`)
      console.log("发帖间隔存储路径:", (postingIntervalsStore as any).path)
      logger.info(`发帖间隔存储路径: ${(postingIntervalsStore as any).path}`)
      logger.info(`直播关注粉丝并破冰存储路径: ${(tkLiveHomeFollowStore as any).path}`)

      // 获取并打印当前存储的数据
      const commentData = commentCyclesStore.store
      const postingData = postingIntervalsStore.store

      console.log("评论周期数据:", JSON.stringify(commentData))
      console.log("发帖间隔数据:", JSON.stringify(postingData))

      // 检查特定键
      const specificCommentKey = "threads_comment_samep45223"
      console.log(`特定评论键 ${specificCommentKey}:`, commentCyclesStore.get(specificCommentKey))

      // 检查键名前缀匹配的所有数据
      const commentKeys = Object.keys(commentData || {}).filter((key) => key.startsWith("threads_comment_"))
      console.log("所有threads_comment_前缀的键:", commentKeys)

      const postingKeys = Object.keys(postingData || {}).filter((key) => key.startsWith("threads_last_post_"))
      console.log("所有threads_last_post_前缀的键:", postingKeys)

      // 可选：创建一个测试键
      // commentCyclesStore.set('test_main_process_key', { timestamp: Date.now(), message: "这是一个测试键" });

      // 根据用户选择是否清空缓存
      if (true) {
        // 这里可以改为用户确认的条件
        commentCyclesStore.clear()
        postingIntervalsStore.clear()
        addFbGroupCountObjStore.clear()
        fbPostingGroupCycleStore.clear()
        tkLiveHomeFollowStore.clear()
        console.log("Electron Store缓存已清理")
        logger.info("Electron Store缓存已清理")
        win.webContents.send("cache-cleared", {
          success: true,
          message: "应用数据缓存已成功清理",
        })
      } else {
        console.log("用户取消清理操作")
        logger.info("用户取消清理操作")
        win.webContents.send("cache-cleared", {
          success: true,
          message: "用户取消清理操作",
        })
      }
    } catch (err: any) {
      console.error("清理缓存时出错:", err)
      logger.error(`清理缓存时出错: ${err.message || err}`)
      win.webContents.send("cache-cleared", {
        success: false,
        message: "清理缓存失败: " + err.message,
      })
    }
  }
})

// 扫描并列出所有electron-store文件
function scanStoreFiles() {
  try {
    const fs = require("fs")

    // 检查多个可能的存储位置
    const possiblePaths = [
      path.join(process.env.APP_ROOT || "", ".config"),
      path.join(app.getPath("userData")),
      path.join(app.getPath("userData"), ".config"),
      path.join(os.homedir(), ".config", "node-exe"),
      path.join(os.homedir(), ".config"),
    ]

    console.log("正在扫描以下目录查找electron-store文件:")
    possiblePaths.forEach((dirPath, index) => {
      console.log(`[${index + 1}] ${dirPath}`)

      try {
        if (fs.existsSync(dirPath)) {
          const files = fs.readdirSync(dirPath)
          const storeFiles = files.filter((file) => file.endsWith(".json"))

          if (storeFiles.length > 0) {
            console.log(`  在 ${dirPath} 中找到 ${storeFiles.length} 个JSON文件:`)
            storeFiles.forEach((file) => {
              try {
                const filePath = path.join(dirPath, file)
                const stats = fs.statSync(filePath)
                const content = fs.readFileSync(filePath, "utf8")
                let dataPreview = ""

                try {
                  const data = JSON.parse(content)
                  // 检查是否有相关键
                  const relevantKeys = Object.keys(data).filter((key) => key.includes("threads_") || key.includes("comment") || key.includes("posting"))
                  dataPreview = relevantKeys.length ? `包含相关键: ${relevantKeys.join(", ")}` : "无相关数据"
                } catch (e) {
                  dataPreview = "无法解析JSON"
                }

                console.log(`    - ${file} (${stats.size} 字节) - ${dataPreview}`)
              } catch (err) {
                console.log(`    - ${file} (无法读取文件内容)`)
              }
            })
          } else {
            console.log(`  目录存在但没有找到JSON文件`)
          }
        } else {
          console.log(`  目录不存在`)
        }
      } catch (err) {
        console.log(`  无法读取目录: ${err.message}`)
      }
    })
  } catch (err) {
    console.error("扫描存储文件时出错:", err)
  }
}

// 添加刷新token的处理器
ipcMain.handle("refresh-token", async (event) => {
  console.log("主进程收到刷新token请求")
  try {
    // 这里可以实现从主进程发送刷新token的请求
    // 由于这是一个示例，我们只是简单地从窗口加载登录页
    const win = BrowserWindow.fromWebContents(event.sender) || BrowserWindow.getAllWindows()[0]

    if (win) {
      // 通知渲染进程token已失效
      win.webContents.send("auth-token-expired", {
        message: "登录状态已过期，正在重定向到登录页",
        status: 401,
      })
      return { success: true }
    }
    return { success: false, error: "无法获取当前窗口" }
  } catch (error) {
    console.error("刷新token失败:", error)
    return { success: false, error: error.message }
  }
})

// 打开日志文件目录
ipcMain.handle("open-logs-directory", () => {
  logger.info("收到打开日志目录请求")
  return openLogsDirectory()
})

// 添加强制退出处理器，用于渲染进程请求强制退出
ipcMain.handle("force-quit-app", async () => {
  logger.info("收到渲染进程强制退出请求")
  await performCleanExit()
  return { success: true }
})

// 如果主进程发现401错误，可以通过这个方法强制窗口导航到登录页
function redirectToLogin(win: BrowserWindow) {
  if (!win || win.isDestroyed()) return

  console.log("主进程强制导航到登录页")
  const url = VITE_DEV_SERVER_URL || `file://${indexHtml}`
  win.loadURL(`${url}#/login`)
}

ipcMain.handle("update-posting-interval", (event, accountId: string, timestamp: number) => {
  try {
    const postingIntervalsStore = createNamedStore("posting-intervals")
    const cacheKey = `threads_last_post_${accountId}`
    postingIntervalsStore.set(cacheKey, timestamp)
    return { success: true }
  } catch (err: any) {
    console.error(`更新账号 ${accountId} 的发帖间隔失败:`, err)
    return { success: false, error: err.message }
  }
})

ipcMain.handle("update-comment-cycle", (event, accountId: string, data: any) => {
  try {
    const commentCyclesStore = createNamedStore("comment-cycles")
    const cacheKey = `threads_comment_cycle_${accountId}`
    commentCyclesStore.set(cacheKey, data)
    return { success: true }
  } catch (err: any) {
    console.error(`更新账号 ${accountId} 的评论周期失败:`, err)
    logger.error(`更新账号 ${accountId} 的评论周期失败: ${err.message || err}`)
    return { success: false, error: err.message }
  }
})

// 获取日志文件路径，便于在应用中查看日志
ipcMain.handle("get-log-path", () => {
  try {
    // 从logger模块动态获取日志路径
    // 尝试通过检查transports获取日志目录
    let logsDir = ""
    for (const transport of logger.transports) {
      // 由于TypeScript类型问题，使用any类型断言来访问filename属性
      const fileTransport = transport as any
      if (fileTransport.filename) {
        logsDir = path.dirname(fileTransport.filename)
        break
      }
    }

    // 如果通过上面的方法找不到，则使用默认路径
    if (!logsDir) {
      const isProduction = app.isPackaged
      const basePath = isProduction ? path.dirname(app.getPath("exe")) : process.env.APP_ROOT || app.getAppPath()
      logsDir = path.join(basePath, "mainLogs")
    }

    // 确保目录存在
    if (!fs.existsSync(logsDir)) {
      fs.mkdirSync(logsDir, { recursive: true })
    }

    const logFiles = fs.readdirSync(logsDir).filter((file) => file.endsWith(".log"))

    logger.info(`获取日志文件列表: ${logFiles.join(", ")}`)

    return {
      success: true,
      logsDir,
      logFiles: logFiles.map((file) => ({
        name: file,
        path: path.join(logsDir, file),
        size: fs.statSync(path.join(logsDir, file)).size,
        lastModified: fs.statSync(path.join(logsDir, file)).mtime,
      })),
    }
  } catch (err: any) {
    logger.error(`获取日志路径失败: ${err.message || err}`)
    return { success: false, error: err.message || String(err) }
  }
})

// 执行干净的退出过程
async function performCleanExit() {
  logger.info("开始执行干净退出程序")

  // 设置退出标志
  app.isQuitting = true

  // 设置一个安全的超时时间，无论如何都会强制退出
  const forceExitTimeout = setTimeout(() => {
    logger.warn("干净退出超时，强制结束进程")
    // 使用process.exit(0)强行终止进程
    process.exit(0)
  }, 10000) // 10秒后强制退出

  try {
    // 1. 停止自动化服务
    if (isAutomationRunning) {
      logger.info("正在停止自动化服务...")
      await stopAutomationService()
    }

    // 断开MQTT连接
    logger.info("断开MQTT连接...")
    mqttService.disconnect()

    // 2. 清理进程
    if (process.platform === "win32") {
      await cleanupWindowsProcesses()
    } else {
      await cleanupUnixProcesses()
    }

    // 3. 完成日志记录
    logger.info("清理完成，准备退出应用")
    logShutdown()

    // 4. 设置强制退出标志，这样窗口可以真正关闭
    forceQuit = true

    // 清除强制退出定时器，因为我们将正常退出
    clearTimeout(forceExitTimeout)

    // 5. 给一点时间完成日志写入
    setTimeout(() => {
      // 关闭所有可能存在的窗口
      for (const window of allWindows) {
        if (!window.isDestroyed()) {
          window.destroy()
        }
      }

      // 清空窗口数组
      allWindows = []

      // 退出应用
      app.quit()
    }, 300)
  } catch (error) {
    // 清除强制退出定时器，因为我们将立即执行自己的强制退出
    clearTimeout(forceExitTimeout)

    logger.error(`执行干净退出时出错: ${error.message || error}`)

    // 即使出错也要强制退出
    forceQuit = true
    setTimeout(() => process.exit(0), 500)
  }
}

// Windows平台专用清理进程方法
async function cleanupWindowsProcesses() {
  try {
    logger.info("执行Windows专用进程清理...")

    // 使用通用命令终止潜在的相关Node进程
    spawn("taskkill", ["/F", "/FI", "IMAGENAME eq node.exe", "/T"], {
      shell: true,
      stdio: "ignore",
    })

    // 等待进程清理完成
    await new Promise((resolve) => setTimeout(resolve, 500))
    return true
  } catch (err) {
    logger.error(`Windows进程清理失败: ${err.message || err}`)
    return false
  }
}

// Unix平台专用清理进程方法
async function cleanupUnixProcesses() {
  try {
    logger.info("执行Unix专用进程清理...")

    // 使用pkill找到并终止与应用相关的所有Node进程
    const appPath = process.env.APP_ROOT || ""

    // 关闭与ads_puppeteer.js相关的进程
    spawn("pkill", ["-f", "puppeteer_ads/ads_puppeteer.js"], {
      shell: true,
      stdio: "ignore",
    })

    // 关闭可能与我们应用相关的其他Node进程
    if (appPath) {
      spawn("pkill", ["-f", path.basename(appPath)], {
        shell: true,
        stdio: "ignore",
      })
    }

    // 关闭与electron-store相关的进程
    spawn("pkill", ["-f", "electron-store-nodejs"], {
      shell: true,
      stdio: "ignore",
    })

    await new Promise((resolve) => setTimeout(resolve, 500))
    return true
  } catch (err) {
    logger.error(`Unix进程清理失败: ${err.message || err}`)
    return false
  }
}

// 创建应用菜单，包含明确的退出选项
function createApplicationMenu() {
  if (process.platform === "darwin") {
    // macOS平台菜单
    const template = [
      {
        label: app.name,
        submenu: [
          { role: "about" },
          { type: "separator" },
          {
            label: "退出",
            accelerator: "Command+Q",
            click: async () => {
              logger.info("用户从菜单选择退出应用")
              await performCleanExit()
            },
          },
        ],
      },
      // 可以添加其他菜单项...
    ]
    Menu.setApplicationMenu(Menu.buildFromTemplate(template as any))
  } else {
    // Windows/Linux平台菜单
    const template = [
      {
        label: "文件",
        submenu: [
          {
            label: "退出",
            accelerator: "Alt+F4",
            click: async () => {
              logger.info("用户从菜单选择退出应用")
              await performCleanExit()
            },
          },
        ],
      },
      // 可以添加其他菜单项...
    ]
    Menu.setApplicationMenu(Menu.buildFromTemplate(template as any))
  }
}

// 设置进程信号处理，确保干净退出
function setupProcessSignalHandlers() {
  // 处理 SIGTERM 信号 (通常是系统发送的终止信号)
  process.on("SIGTERM", async () => {
    logger.info("收到 SIGTERM 信号，准备干净退出")
    await performCleanExit()
  })

  // 处理 SIGINT 信号 (通常是用户按Ctrl+C)
  process.on("SIGINT", async () => {
    logger.info("收到 SIGINT 信号，准备干净退出")
    await performCleanExit()
  })

  // Windows平台特有的处理
  if (process.platform === "win32") {
    try {
      // 使用CTRL_CLOSE_EVENT进行优雅关闭 (Windows特有)
      process.on("message", async (msg) => {
        if (msg === "graceful-exit") {
          logger.info("收到 graceful-exit 消息，准备干净退出")
          await performCleanExit()
        }
      })
    } catch (e) {
      logger.warn(`无法设置Windows特有的进程消息处理器: ${e}`)
    }
  }
}

// Add a helper function to capture automation errors
function captureAutomationError(error: any) {
  errorHandler.captureError({
    type: "automationError",
    message: error.message || String(error),
    stack: error.stack,
    source: "automation",
  })
}

// Add API to expose manual error reporting from IPC
ipcMain.handle("report-error", (event, error) => {
  errorHandler.captureError({
    type: error.type || "customError",
    message: error.message || "Unknown error",
    stack: error.stack,
    info: error.info,
    source: error.source || "main",
  })
  return true
})

// 设置IPC处理程序处理MQTT请求
function setupMqttIpcHandlers() {
  // 连接MQTT
  ipcMain.handle("mqtt:connect", async (event, config) => {
    try {
      if (config?.deviceIdList) {
        mqttService.setDeviceIdList(config.deviceIdList)
      }

      if (config?.mode) {
        mqttService.setMode(config.mode)
      }

      const success = mqttService.connect()
      return { success }
    } catch (error: any) {
      logger.error(`[IPC] MQTT connect error: ${error.message}`)
      return { success: false, error: error.message }
    }
  })

  // 断开MQTT连接
  ipcMain.handle("mqtt:disconnect", async () => {
    try {
      mqttService.disconnect()
      return { success: true }
    } catch (error: any) {
      logger.error(`[IPC] MQTT disconnect error: ${error.message}`)
      return { success: false, error: error.message }
    }
  })

  // 发布MQTT消息
  ipcMain.handle("mqtt:publish", async (event, { topic, message, options }) => {
    try {
      const success = mqttService.publish(topic, message, options)
      return { success }
    } catch (error: any) {
      logger.error(`[IPC] MQTT publish error: ${error.message}`)
      return { success: false, error: error.message }
    }
  })

  // 订阅MQTT主题
  ipcMain.handle("mqtt:subscribe", async (event, { topics }) => {
    try {
      const success = mqttService.subscribe(topics)
      return { success }
    } catch (error: any) {
      logger.error(`[IPC] MQTT subscribe error: ${error.message}`)
      return { success: false, error: error.message }
    }
  })
}

